package testApplets;

import java.applet.Applet;
import java.util.ArrayList;
import java.util.Vector;

import peasy.PeasyCam;
import processing.core.PApplet;

import meshToSolid.ContainerGrid;
import meshToSolid.ContainerGrid.Container;

import simpleGeom.Box3D;
import simpleGeom.Mesh;
import simpleGeom.MeshEdge;
import simpleGeom.MeshFace;
import simpleGeom.MeshNode;
import simpleGeom.SegPreCalc;
import simpleGeom.Triangle3D;
import simpleGeom.TrianglePreCalc;
import simpleGeom.Vec3D;

public class RepairMeshApplet extends PApplet {
Mesh mesh;
ContainerGrid grid;
ArrayList<MeshEdge> cutEdges=new ArrayList<MeshEdge>();
ArrayList<MeshNode> cutNodes=new ArrayList<MeshNode>();
public void setup(){
	size(800,800,P3D);
	mesh=new Mesh();
	String file="/Users/caad/Desktop/Archive/complete/final1e.obj";
			
	mesh.loadMesh(file);
	mesh.triangulate();
	Box3D bounds=mesh.getBounds();
	PeasyCam cam=new PeasyCam(this,bounds.getMaxDimension()*50);
	split();
	connect();
}
public MeshEdge addCutEdge(MeshNode n1,MeshNode n2){
	MeshEdge edge = new MeshEdge(n1, n2);
	edge.attach();
	cutEdges.add(edge);
	return edge;
}
public void connect(){
	for (int i=0;i<mesh.getNFaces();i++){
		MeshFace face=mesh.getFace(i);
		splitTriangle(face);
	}
	for (int i=0;i<cutNodes.size();i++){
		MeshNode n=cutNodes.get(i);
		println(n.getEdges().size());// why sometimes 0 or 2?  intersectionpoint splits edge==2 and face==2
	}
}

	public void splitTriangle(MeshFace face) {
		IData fData = (IData) face.getData();
		ArrayList<Intersection> edgeDatas = getEdgeIntersections(face);
		ArrayList<MeshFace> intersectingFaces = new ArrayList<MeshFace>();
		ArrayList<MeshEdge> newEdges = new ArrayList<MeshEdge>();
		if (fData != null) {
			// internal edges
			for (int i = 0; i < fData.intersections.size() - 1; i++) {
				Intersection is1 = fData.intersections.get(i);
				for (int j = i + 1; j < fData.intersections.size(); j++) {
					Intersection is2 = fData.intersections.get(j);
					if (hasSameFaceFF(is1, is2)) {
						newEdges.add(addCutEdge(is1.node, is2.node));
					}
				}
			}
			// border edges from border to inner Intersection
			for (int i = 0; i < edgeDatas.size(); i++) {
				Intersection is1 = edgeDatas.get(i);
				for (int j = 0; j < fData.intersections.size(); j++) {
					Intersection is2 = fData.intersections.get(j);
					if (hasSameFaceEF(is1, is2)) {
						newEdges.add(addCutEdge(is1.node, is2.node));
					}
				}
			}
		}
		// direct connections from Edge To Edge
		for (int i = 0; i < edgeDatas.size() - 1; i++) {
			Intersection is1 = edgeDatas.get(i);
			for (int j = i + 1; j < edgeDatas.size(); j++) {
				Intersection is2 = edgeDatas.get(j);
				if (hasSameFaceEE(is1, is2)) {
					newEdges.add(addCutEdge(is1.node, is2.node));
				}
			}
		}
		// alle nodes
		// alle edges
	}

	public boolean hasSameFaceEE(Intersection i1,Intersection i2){
		MeshFace f1=i1.face;
		MeshFace f2=i2.face;
		if (f1!=null&&f2!=null){
			if (f1==f2)return true;
		}
		return false;
	}
public boolean hasSameFaceEF(Intersection i1,Intersection i2){
	MeshFace f1=i1.face;
	MeshFace f3=i2.edge.getFace1();
	MeshFace f4=i2.edge.getFace2();
	if (f1!=null&&f3!=null){
		if (f1==f3)return true;
	}
	if (f1!=null&&f4!=null){
		if (f1==f4)return true;
	}
	return false;
}
public boolean hasSameFaceFF(Intersection i1,Intersection i2){
	MeshFace f1=i1.edge.getFace1();
	MeshFace f2=i1.edge.getFace2();
	MeshFace f3=i2.edge.getFace1();
	MeshFace f4=i2.edge.getFace2();
	if (f1!=null&&f3!=null){
		if (f1==f3)return true;
	}
	if (f1!=null&&f4!=null){
		if (f1==f4)return true;
	}
	if (f2!=null&&f3!=null){
		if (f2==f3)return true;
	}
	if (f2!=null&&f4!=null){
		if (f2==f4)return true;
	}
	return false;
}
public ArrayList<Intersection>getEdgeIntersections(MeshFace face){
	ArrayList<MeshEdge>edges=face.getEdges();
	ArrayList<Intersection>edgeDatas=new ArrayList<Intersection>();
	for (int i=0;i<edges.size();i++){
		MeshEdge edge=edges.get(i);
		if (edge.getData()!=null){
			IData eData=(IData)edge.getData();
			edgeDatas.addAll(eData.intersections);
		}
	}
	return edgeDatas;
}
public void split(){
	Box3D bounds=mesh.getBounds();
	grid=new ContainerGrid(bounds,bounds.getMaxDimension()/1000f);
	println("nX: "+grid.nX+"nY: "+grid.nY+"nZ: "+grid.nZ);
	
	for (int i=0;i<mesh.getNFaces();i++){
		MeshFace face=mesh.getFace(i);
		TrianglePreCalc tri=new TrianglePreCalc(face.getNode(0),face.getNode(1),face.getNode(2));
		grid.addObject(face,tri);
	}
	
	System.out.println("start Edges");
	for (int i=0;i<mesh.getNEdges();i++){
		MeshEdge edge=mesh.getEdge(i);
		SegPreCalc seg=new SegPreCalc(edge.getP1(),edge.getP2());
		Box3D bds=edge.getBounds3D();
		//bds=bds.getOffsetBox(0.001f);
		Vector<Object>faces=grid.getObjects(bds,seg);
		if (i%100000==0){
			println(i+" / "+mesh.getNEdges());
			println("faces" +faces.size());
		}
		for (int j=0;j<faces.size();j++){
			MeshFace face=(MeshFace) faces.get(j);
			if (face!=edge.getFace1()&&face!=edge.getFace2()){
				if (!face.contains(edge.getNode1())&&!face.contains(edge.getNode2())){
					Triangle3D tri=new Triangle3D(face.getNode(0),face.getNode(1),face.getNode(2));
					Vec3D iP=tri.intersectSegTriangle(edge.getP1(), edge.getP2());
					if (iP!=null){
						MeshNode node=new MeshNode(iP.getX(),iP.getY(),iP.getZ());
						cutNodes.add(node);
						
						IData eData=new IData();
						if (edge.getData()!=null)eData=(IData) edge.getData();
						else edge.setData(eData);
						
						IData fData=new IData();
						if (face.getData()!=null)fData=(IData) face.getData();
						else face.setData(fData);
						
						Intersection eI=new Intersection(node,edge,face);
						eData.intersections.add(eI);
						fData.intersections.add(eI);
					}
				}
			}
		}
	}
}
public void draw(){
	background(0);
	lights();
	scale(50);
	//mesh.display3D(g);
	noFill();
	stroke(255,0,0);
	for (int x=0;x<grid.nX;x++){
		for (int y=0;y<grid.nY;y++){
			for (int z=0;z<grid.nY;z++){
				Container c=grid.get(x, y, z);
				if (c!=null){
				ArrayList<Object>faces=c.objects;
				for (int i=0;i<faces.size();i++){
					
					MeshFace face=(MeshFace)faces.get(i);
					//if (face.getData()!=null||getEdgeIntersections(face).size()>0){
					face.display3D(g);
					//}
				}
				}
			}
		}
	}
	fill(255);
	for (int i=0;i<mesh.getNEdges();i++){
		MeshEdge edge=mesh.getEdge(i);
		if (edge.getData()!=null){
			IData data=(IData) edge.getData();
			for (int j=0;j<data.intersections.size();j++){
				Intersection is=data.intersections.get(j);
				Vec3D n=is.node;
				pushMatrix();
				translate(n.x,n.y,n.z);
				box(0.001f);
				popMatrix();
			}
		}
	}
	stroke(0,255,0);
	for (int i=0;i<cutEdges.size();i++){
		MeshEdge edge=cutEdges.get(i);
		edge.display3D(g);
	}
}

class IData{
	ArrayList<Intersection>intersections=new ArrayList<Intersection>();
}

class Intersection{
	Intersection(MeshNode node,MeshEdge edge,MeshFace face){
		this.node=node;
		this.face=face;
		this.edge=edge;
	}
	MeshEdge edge;
	MeshNode node;
	MeshFace face;
}

}
